package com.ruoyi.common.utils;

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import com.ruoyi.project.wenyanwen.tag.domain.ArticleTag;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

public class JsonUtil {

    public final static String NORM_DATETIME_PATTERN = "yyyy-MM-dd HH:mm:ss";

    public final static String NORM_DATE_PATTERN = "yyyy-MM-dd";

    public final static String NORM_TIME_PATTERN = "HH:mm:ss";


    private static Logger logger = LoggerFactory.getLogger(JsonUtil.class);
    private static final ObjectMapper mapper = new ObjectMapper();
    private static final ObjectMapper mapperIgnoreUnknownField = new ObjectMapper();// 忽略不存在的字段.

    static {

        JavaTimeModule module = new JavaTimeModule();
        module.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(NORM_DATETIME_PATTERN)));
        module.addSerializer(new LocalTimeSerializer(DateTimeFormatter.ofPattern(NORM_TIME_PATTERN)));
        module.addSerializer(new LocalDateSerializer(DateTimeFormatter.ofPattern(NORM_DATE_PATTERN)));
        module.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(NORM_DATE_PATTERN)));
        module.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern(NORM_TIME_PATTERN)));

        mapper.registerModule(module);
        mapperIgnoreUnknownField.registerModule(module);
        mapperIgnoreUnknownField.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);


    }

    public static String toJson(Object obj) {
        String json = null;
        try {
            if (obj != null) {
                json = mapper.writeValueAsString(obj);
            }
            return json;
        } catch (Exception e) {
            logger.warn(e.getMessage());
        }

        return json;
    }

    public static <T> T toObject(String json, Class<T> clazz, boolean ignoreUnknownField) {
        if (json == null || json.length() == 0) {
            return null;
        }

        try {
            if (ignoreUnknownField) {
                return mapperIgnoreUnknownField.readValue(json, clazz);
            } else {
                return mapper.readValue(json, clazz);
            }
        } catch (Exception e) {
            logger.warn(e.getMessage());
        }

        return null;
    }

    public static <T> List<T> toListObject(String content, Class<T> valueType) {
        if (content == null || content.length() == 0) {
            return null;
        }

        try {
            return mapper.readValue(content, mapper.getTypeFactory().constructParametricType(List.class, valueType));
        } catch (Exception e) {
            logger.error(e.getMessage());
        }

        return null;
    }

    public static <T> List<T> toObject(List<String> jsonList, Class<T> valueType) {
        return toObject(jsonList, valueType, true);
    }

    public static <T> List<T> toObject(List<String> jsonList, Class<T> valueType, boolean ignoreUnknownField) {
        List<T> list = new ArrayList<T>();
        if (jsonList == null || jsonList.isEmpty()) {
            return list;
        }
        for (String json : jsonList) {
            list.add(JsonUtil.toObject(json, valueType, ignoreUnknownField));
        }
        return list;
    }

    @SuppressWarnings("unchecked")
    public static Map<String, Object> toMap(String content) {
        return JsonUtil.toObject(content, Map.class);
    }

    @SuppressWarnings("unchecked")
    public static Set<Object> toSet(String content) {
        return JsonUtil.toObject(content, Set.class);
    }

    @SuppressWarnings("unchecked")
    public static <T> Map<String, T> toMap(String json, Class<T> clazz) {
        return JsonUtil.toObject(json, Map.class);
    }

    @SuppressWarnings("unchecked")
    public static <T> Set<T> toSet(String json, Class<T> clazz) {
        return JsonUtil.toObject(json, Set.class);
    }

    @SuppressWarnings("unchecked")
    public static Map<String, Object> toNotNullMap(String json) {
        Map<String, Object> map = JsonUtil.toObject(json, Map.class);
        if (map == null) {
            map = new LinkedHashMap<String, Object>();
        }
        return map;
    }

    @SuppressWarnings("unchecked")
    public static <T> Map<String, T> toNotNullMap(String json, Class<T> clazz) {
        Map<String, T> map = JsonUtil.toObject(json, Map.class);
        if (map == null) {
            map = new LinkedHashMap<String, T>();
        }
        return map;
    }

    @SuppressWarnings("unchecked")
    public static <T> Set<T> toNotNullSet(String json, Class<T> clazz) {
        Set<T> set = JsonUtil.toObject(json, Set.class);
        if (set == null) {
            set = new LinkedHashSet<T>();
        }
        return set;
    }

    /**
     * 类型转换.
     *
     * @param obj
     * @param clazz
     * @param <T>
     * @return
     */
    @Deprecated
    public static <T> T convert(Object obj, Class<T> clazz) {
        String json = JsonUtil.toJson(obj);
        return toObject(json, clazz);
    }

    /**
     * 将Json转换成对象.
     *
     * @param json
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T> T toObject(String json, Class<T> clazz) {
        return toObject(json, clazz, true);
    }

    public static void main(String[] args) {

        Map<String, Object> tag = new HashMap<>();
        tag.put("createTime", LocalDateTime.now());
        //tag.setCreateTime(LocalDateTime.now());
        String json = JsonUtil.toJson(tag);
        System.out.println(json);
        ArticleTag tag2 = JsonUtil.toObject(json, ArticleTag.class);
    }

}
